package xnj.lazydog.btcontroller.ControlViews;

import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.TypedValue;
import android.view.Display;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;

import java.util.ArrayList;
import java.util.List;

import xnj.lazydog.btcontroller.ControlViews.ControlViews.ControlElement;
import xnj.lazydog.btcontroller.R;

public class ControlView extends View {

    private static final String TAG = "ControlView";
    public static Resources resources;

    Paint p;
    public float w,h;
    Project project;
    ControlElement selectedToy;
    int selectedIndex=-1;
    List<ControlElement> toys = new ArrayList<>();
    boolean isForDesign = false;
    boolean isForSnap = false;
    static float mm2pix_k;

    public int editMode = 0;

    public boolean isDialogShowing=false;

    RectF rectF;

    int sw_mm,sh_mm;

    public static Context context;

    public static void  bigSmall(final View view)
    {
        Animation a = AnimationUtils.loadAnimation(context, R.anim.big_small);
        final Animation b = AnimationUtils.loadAnimation(context,R.anim.big_small_2);

        a.setAnimationListener(new Animation.AnimationListener() {
            @Override
            public void onAnimationStart(Animation animation) {
            }
            @Override
            public void onAnimationEnd(Animation animation) {
                view.startAnimation(b);
            }
            @Override
            public void onAnimationRepeat(Animation animation) {
            }
        });
        view.startAnimation(a);
    }



    public ControlView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initPIXMM();


        this.context = context;
        resources = getResources();
        info_x_pix = mm2Pix(2);
        info_height_pix = mm2Pix(3);
        info_y_pix = h-mm2Pix(1.5f)-info_height_pix*5f;
        rectF = new RectF(info_x_pix*0.5f,info_y_pix+mm2Pix(0.4f),mm2Pix(18),h-mm2Pix(0.5f));
        p = new Paint();
        p.setTextSize(info_height_pix*0.7f);
        p.setAntiAlias(true);
    }



    /**  根据工程配置对象 初始化 控制视图
     * @param project 工程配置对象，包含了所有界面布局、数据链接有关的配置
     */
    public void init(Project project)
    {
        generateToys(project);
    }


    /**  生成用于和用户交互的即时控件
     *   每个即时控件需要有一个对应的ViewOptions配置才可工作
     *   即时控件的数据分为两部分，一部分是框架部分，一部分是配置部分。
     *   本函数的功能是生成控件的框架部分，并将工程中的配置部分分配到控件中
     * @param project 用于加载 即时控件 的工程配置对象
     */
    public void generateToys(Project project)
    {
        Link link;
        this.project = project;
        for(int i=0;i<project.elements.size();i++)
        {
            toys.add(ControlElement.newInstance(project.elements.get(i)));
            toys.get(i).updatePix();
            for (int j=0;j<6;j++) {  ////  初始化链接变量
                link = project.elements.get(i).links[j];
                if(link!=null)   // 链接存在
                {
                    if(project.values[link.dir][link.type].size()>link.index) {  // 索引是有效的

                    toys.get(i).linkedValues[j] = project.values[link.dir][link.type].get(link.index);

                    if(link.dir==0)
                        toys.get(i).valuesName[j] = project.txData[link.type].get(link.index);
                    else
                        toys.get(i).valuesName[j] = project.rxData[link.type].get(link.index);

                    toys.get(i).data_dir_tx[j] = link.dir==0;

                    Log.w(TAG, "link value"+ i+"  "+j+" "+toys.get(i).linkedValues[j].type);

                    }else
                    {
                        if(link.dir==0)
                        {
                            if(project.txData[link.type].size()>link.index)
                            {
                                int k = project.txData[link.type].size()-project.values[0][link.type].size();
                                for(int l=0;l<k;l++)
                                    project.values[0][link.type].add(new Value(link.type));
                            }
                        }else
                        {
                            if(project.rxData[link.type].size()>link.index)
                            {
                                int k = project.rxData[link.type].size()-project.values[1][link.type].size();
                                for(int l=0;l<k;l++)
                                    project.values[1][link.type].add(new Value(link.type));
                            }
                        }
                    }
                }
            }
            //Log.w(TAG, "generateToys: "+project.elements.get(i).uiType );
        }
        if(isForDesign&&toys.size()>0)     //// 在设计模式下，自动将第一个控件选定为编辑控件，控件只有被选定后，才可对其布局参数、专有配置进行编辑
            selectToy(-1);
    }


    /** 添加控件
     *   在运行时，唯一的添加的方式就是点击"添加"按钮，
     *   1.弹出类型选择对话框，选定uiType
     *   2.然后弹出数据链接对话框，选定数据链接情况，初始化好link数组
     *   3.最后弹出专有配置（类型相关配置），对不同类型的控件有不同的配置流程和布局
     *           设置好专有配置后即可添加
     *   X.以上的任何一步没有通过者，都无法执行以下的控件添加程序
     * @param options 带有 专有配置的配置对象
     */
    void addNewToy(ViewOptions options)
    {
        options = addLayoutOptions(options);

        project.elements.add(options);  //// 工程对象 添加 控件配置

        configureOptions(options);
        toys.add(ControlElement.newInstance(options)); //// 根据配置 生成 即时控件对象

        selectToy(toys.size()-1);

        selectedToy.setPositionImm(sw_mm/2,sh_mm/2);
        for(ControlElement el:toys)     //// 打印所有控件
            Log.w(TAG, "Toy: "+el.options.uiType);
    }

    void configureOptions(ViewOptions op)
    {
        switch (op.uiType)
        {
            case ViewOptions.UI_TYPE_TEXT:

                break;
            case ViewOptions.UI_TYPE_EDIT_TEXT:

                break;
            case  ViewOptions.UI_TYPE_SWITCH:

                op.on_value = 1;
                op.off_value = 0;
                break;
            case  ViewOptions.UI_TYPE_BUTTON:
                op.on_value = 1;
                op.off_value = 0;
                break;
            case  ViewOptions.UI_TYPE_VALUE_BAR:

                op.on_value = 127;
                op.off_value = -128;

                break;
            case  ViewOptions.UI_TYPE_VALUE_DRAG_BAR:

                op.on_value = 127;
                op.off_value = -128;
                break;
            case  ViewOptions.UI_TYPE_2AXIS_STICK:
                op.on_value = 127;
                op.off_value = -128;
                op.on_en = false;
                break;
            case  ViewOptions.UI_TYPE_2AXIS_PLOT:
                op.on_value = 127;
                op.off_value = -128;
                break;
            case  ViewOptions.UI_TYPE_PLOT:

                op.on_value = 1000;
                op.off_value = -1000;
                op.threshold = 100;

                break;
            case  ViewOptions.UI_TYPE_VALUE_BUTTON:
                op.on_value = 0.5f;
                break;
        }
    }


    /**
     *   移除控件
     */
    public void removeToy()
    {
        if(selectedToy!=null) {
            toys.remove(selectedToy);
            project.elements.remove(selectedToy.options);
            if (toys.size() > 0)
                selectToy(toys.size() - 1);
            else
                selectedIndex = -1;
        }
    }


    /**  根据之前已经添加的控件的布局参数，确定一个比较合适的布局参数传给新添加的空间的配置对象
     *   如果已经添加了同类的控件，则将新添加的空间的尺寸设为相同的
     * @param options 要加入布局配置的视图配置
     * @return
     */
    ViewOptions addLayoutOptions(ViewOptions options)
    {

        float x_sum=0,y_sum=0;

        options.deg =0;
        options.w = ViewOptions.DEFAULT_WIDTH[options.uiType];
        options.h = ViewOptions.DEFAULT_HEIGHT[options.uiType];


        for(ControlElement toy:toys)
        {
            x_sum+=toy.options.x;
            y_sum+=toy.options.y;
            if(options.uiType==toy.options.uiType)
            {
                options.deg = toy.options.deg;
                options.w =  toy.options.w;
                options.h =  toy.options.h;
            }
        }



        if(toys.size()>0)
        {
            options.x = sw_mm/2-((int)(x_sum/toys.size())-sw_mm/2);
            options.y = sh_mm/2-((int)(y_sum/toys.size())-sh_mm/2);
        }else {
            options.x = sw_mm/2;
            options.y = sh_mm/2;
        }

        return options;
    }



    RectF selectRect=new RectF();

    float alphaPhase=0;

    float info_height_pix;
    float info_y_pix;
    float info_x_pix;
    int info_x,info_y,info_w,info_h,info_deg;


    float info_alpha = 0;


    boolean toyDrawn;
    @Override
    protected void onDraw(Canvas canvas) {
        w = getWidth();
        h = getHeight();

        for(ControlElement element:toys)
        {
            element.update();
            canvas.save();
            canvas.translate(element.x_pix,element.y_pix);
            canvas.rotate(element.degree);
            element.draw(canvas);
            if(isForDesign&&element==selectedToy)
            {
                alphaPhase+=0.1f;
                p.setARGB((int)(Math.sin(alphaPhase)*127)+127,125,125,125);
                p.setStyle(Paint.Style.STROKE);
                p.setStrokeWidth(select_rect_padding_pix*0.3f);
                selectRect.left = -selectedToy.w_pix*0.5f-select_rect_padding_pix;
                selectRect.right = selectedToy.w_pix*0.5f+select_rect_padding_pix;
                selectRect.top = -selectedToy.h_pix*0.5f-select_rect_padding_pix;
                selectRect.bottom = selectedToy.h_pix*0.5f+select_rect_padding_pix;
                canvas.drawRoundRect(selectRect,select_rect_padding_pix,select_rect_padding_pix,p);
            }

            canvas.restore();
        }

        if(isForDesign)
        {
            if(selectedToy!=null) {
                info_alpha += (1 - info_alpha) * 0.2f;
                info_x = selectedToy.options.x;
                info_y = selectedToy.options.y;
                info_w = selectedToy.options.w;
                info_h = selectedToy.options.h;
                info_deg = selectedToy.options.deg;
            }else
                info_alpha+=(-info_alpha)*0.1f;

            if(info_alpha>0.02f) {
                p.setStyle(Paint.Style.FILL);
                p.setARGB((int) (155 * info_alpha), 55, 55, 55);
                canvas.drawRoundRect(rectF, info_x_pix * 0.5f, info_x_pix * 0.5f, p);
                p.setARGB((int) (255 * info_alpha), 250, 250, 250);
                canvas.drawText("X坐标: " + info_x + "mm", info_x_pix, info_y_pix + info_height_pix, p);
                canvas.drawText("Y坐标: " + info_y + "mm", info_x_pix, info_y_pix + info_height_pix * 2, p);
                canvas.drawText("宽度 : " + info_w + "mm", info_x_pix, info_y_pix + info_height_pix * 3, p);
                canvas.drawText("高度 : " + info_h + "mm", info_x_pix, info_y_pix + info_height_pix * 4, p);
                canvas.drawText("角度 : " + info_deg + "°", info_x_pix, info_y_pix + info_height_pix * 5, p);
            }
        }


        if(isForSnap)
        {

            p.setColor(0xff2ea7e0);
            p.setStyle(Paint.Style.STROKE);
            float sw = w * 0.01f;
            float rad = sw * 10;
            p.setStrokeWidth(sw);
            selectRect.left =  0;
            selectRect.right = w;
            selectRect.top = 0;
            selectRect.bottom = h;
            canvas.drawRoundRect(selectRect,rad,rad,p);

        }


        if(!isDialogShowing)
            invalidate();
    }


    float px,py;
    float p1x,p1y;

    float fx,fy;
    boolean isDragging;
    boolean isZoomed=false;


    public void onTouched(MotionEvent event,boolean hitDog) {

       // if(isDialogShowing) {
//            isDialogShowing = false;
//            postInvalidate();
//        }


        px = event.getX(0);
        py = event.getY(0);

        if(!isForDesign&&event.getPointerCount()>1) {
            p1x = event.getX(1);
            p1y = event.getY(1);

            isZoomed = true;
            if(!isZooming) // 首次缩放
            {
                f_sx = Math.abs(p1x-px);
                f_sy = Math.abs(p1y-py);

                for (int i = toys.size() - 1; i >= 0; i--) {
                    if (toys.get(i).isInArea((px+p1x)*0.5f, (py+p1y)*0.5f, false)) {

                        if(f_sx>f_sy)
                           toys.get(i).zoomMode =1;
                        else
                           toys.get(i).zoomMode =2;
                        toys.get(i).zoom_started();
                        break;
                    }
                }
            }else
            {
                zoomed(Math.abs(p1x-px)/f_sx  ,  Math.abs(p1y-py)/f_sy );
            }
            isZooming = true;
        }else {

            for (int i = toys.size() - 1; i >= 0; i--) {
                if(toys.get(i).zoomMode>0)
                    toys.get(i).zoomMode=0;
            }
            isZooming = false;
        }
        ///Log.w(TAG, "onTouched"+px+"- -"+py+"- -"+p1x+"- -"+p1y);


        if(event.getPointerCount()==1) {
            if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
                isDirectlyDragging = false;
                isDragging = false;
                fx = px;
                fy = py;
                pressed();
            }
            if (event.getActionMasked() == MotionEvent.ACTION_MOVE) {

                if ((px - fx) * (px - fx) + (py - fy) * (py - fy) > 400) {

                    if ( isForDesign&&!isDragging) {
                        if (!hitDog) {
                            for (int i = toys.size() - 1; i >= 0; i--) {
                                isToyTouched = toys.get(i).isInArea(px, py, true);
                                if (isToyTouched) {
                                    selectToy(i);
                                    fx = px;
                                    fy = py;
                                    isDirectlyDragging = true;
                                    toy_fx = selectedToy.options.x;
                                    toy_fy = selectedToy.options.y;
                                    toy_fw = selectedToy.options.w;
                                    toy_fh = selectedToy.options.h;
                                    toy_f_deg = selectedToy.options.deg;
                                    break;
                                }
                            }

                        }
                    }
                    isDragging = true;
                }
                if (isDragging) {
                    dragged();
                }
            }
            if (event.getActionMasked() == MotionEvent.ACTION_UP) {
                if (!isDragging&&!isZoomed) {
                    clicked(hitDog);
                }
                released();
                isZoomed = false;
                isDragging = false;
                isDirectlyDragging = false;
            }
        }
    }


    float f_sx,f_sy;
    boolean isZooming = false;
    void zoomed(float x,float y)
    {

        for (int i = toys.size() - 1; i >= 0; i--) {
            if (toys.get(i).zoomMode>0) {
                toys.get(i).zoomed(x,y);
                break;
            }
        }


    }


    int toy_fx,toy_fy;
    int toy_fw,toy_fh;
    int toy_f_deg;

    void pressed()
        {
            if (isForDesign) {
                if (selectedToy != null) {

                    if (selectedToy.isInArea(px, py, true))
                        isDirectlyDragging = true;

                    //Log.w(TAG, "pressed: " + isDirectlyDragging + "  " + selectedToy.rx + " " + selectedToy.ry);
                    toy_fx = selectedToy.options.x;
                    toy_fy = selectedToy.options.y;
                    toy_fw = selectedToy.options.w;
                    toy_fh = selectedToy.options.h;
                    toy_f_deg = selectedToy.options.deg;
                }
            } else {
                for (int i = toys.size() - 1; i >= 0; i--) {
                    isToyTouched = toys.get(i).isInArea(px, py, false);
                    if (isToyTouched) {
                        toys.get(i).isPressed = true;
                        toys.get(i).pressed();

                        //toyListener.onToyValueChanged();
                        break;
                    }
                }

            }

    }

    void released()
    {
        for(int i=0;i<toys.size();i++) {
            if(toys.get(i).isPressed)
                toys.get(i).released();

            toys.get(i).isPressed = false;
        }
    }

    boolean isDirectlyDragging =false;

    void dragged() {

        if (isForDesign)
        {

            int x,y;

            if(selectedToy!=null)
            {
                switch (editMode)
                {
                    case 0:

                        if(isDirectlyDragging) {
                            x = toy_fx + (int) pix2MM(px - fx);
                            y = toy_fy + (int) pix2MM(py - fy);
                        }else
                        {
                            x = toy_fx + (int) pix2MM((px - fx)*0.25f);
                            y = toy_fy + (int) pix2MM((py - fy)*0.25f);
                        }

                        if(x<0)
                            x = 0;
                        if(y<0)
                            y=0;

                        if(x>sw_mm)
                            x = sw_mm;
                        if(y>sh_mm)
                            y = sh_mm;

                        selectedToy.setPosition(x,y);
                        break;
                    case 1:
                        if(isDirectlyDragging) {
                            x = (int) pix2MM(2*(float)((px-selectedToy.x_pix)*Math.cos(-Math.toRadians(selectedToy.degree))-(py-selectedToy.y_pix)*Math.sin(-Math.toRadians(selectedToy.degree))));
                            y = (int) pix2MM(2*(float)((px-selectedToy.x_pix)*Math.sin(-Math.toRadians(selectedToy.degree))+(py-selectedToy.y_pix)*Math.cos(-Math.toRadians(selectedToy.degree))));
                        }else
                        {
                            x = toy_fw + (int) (pix2MM((float)((px-fx)*Math.cos(-Math.toRadians(selectedToy.degree))-(py-fy)*Math.sin(-Math.toRadians(selectedToy.degree))))*0.25f);
                            y = toy_fh + (int) (pix2MM((float)((px-fx)*Math.sin(-Math.toRadians(selectedToy.degree))+(py-fy)*Math.cos(-Math.toRadians(selectedToy.degree))))*0.25f);
                        }
                        if(x<ViewOptions.MIN_WIDTH[selectedToy.options.uiType])
                            x=ViewOptions.MIN_WIDTH[selectedToy.options.uiType];
                        if(y<ViewOptions.MIN_HEIGHT[selectedToy.options.uiType])
                            y=ViewOptions.MIN_HEIGHT[selectedToy.options.uiType];
                        selectedToy.setScale(x,y);
                        break;
                    case 2:
                        if(isDirectlyDragging) {
                            double deg = Math.toDegrees(Math.atan2(py-selectedToy.y_pix,px-selectedToy.x_pix));
                            x = (int)deg;
                        }else
                        {
                            x = toy_f_deg + (int) pix2MM((px - fx));
                        }
                        selectedToy.setRotation((x/5)*5);
                        break;
                }
            }
        }else
        {

            for(int i=0;i<toys.size();i++) {
             if(toys.get(i).isPressed)
             {
                 toys.get(i).isInArea(px,py,false);
                 toys.get(i).dragged();
             }
            }
        }
    }

    boolean isToyTouched;

    void clicked(boolean hitDog)
    {
        if(isForDesign)//// 在调试模式下
        {
            if(!hitDog) {
                for (int i = toys.size() - 1; i >= 0; i--) {
                    isToyTouched = toys.get(i).isInArea(px, py, true);
                    if (isToyTouched) {
                        selectToy(i);
                        break;
                    }
                }
                if (!isToyTouched) {
                    selectToy(-1);
                }
            }
        }else
        {
            if(!hitDog) {
                for (int i = toys.size() - 1; i >= 0; i--) {
                    isToyTouched = toys.get(i).isInArea(px, py, true);
                    if (isToyTouched) {
                        toys.get(i).clicked(context);
                        break;
                    }
                }
            }
        }
    }


    float select_rect_padding_pix;

    void selectToy(int index)
    {
        if(index>=0) {
            selectedIndex = index;
            selectedToy = toys.get(index);
            select_rect_padding_pix = mm2Pix(ControlElement.SELECT_RECT_PADDING_MM);
            selectRect.left = -selectedToy.w_pix * 0.5f - select_rect_padding_pix;
            selectRect.right = selectedToy.w_pix * 0.5f + select_rect_padding_pix;
            selectRect.top = -selectedToy.h_pix * 0.5f - select_rect_padding_pix;
            selectRect.bottom = selectedToy.h_pix * 0.5f + select_rect_padding_pix;
            alphaPhase = 1.57f;
        }else
        {
            selectedIndex = index;
            selectedToy = null;
        }
    }

    void initPIXMM()
    {
        WindowManager windowManager = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
        if(windowManager!=null) {
            Display display = windowManager.getDefaultDisplay();
            DisplayMetrics metrics = new DisplayMetrics();
            display.getMetrics(metrics);

            //mm2pix_k = (metrics.xdpi + metrics.ydpi) / 50.8f;

            mm2pix_k =TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_MM, 1,metrics);

            //Log.w(TAG, "initPIXMM: "+mm2pix_k );

            w = metrics.widthPixels;
            h = metrics.heightPixels;
        }else {
            w =1080;
            h =1920;
            mm2pix_k = 16;
        }
        sw_mm = (int)pix2MM(w);
        sh_mm = (int)pix2MM(h);
    }
    public static float mm2Pix(float mm)
    {
        return mm*mm2pix_k;

    }

   public static float pix2MM(float pix)
    {
        return pix/mm2pix_k;
    }


    public interface ToyListener{

        void onToyValueChanged();

        void onShowLink(ControlElement element);

        void onPicture(boolean ok);

    }

    public void initToyValueListener(ToyListener listener)
    {
        for(int i=0;i<toys.size();i++)
        {
            toys.get(i).toyListener = listener;
        }
    }
}
